﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Diagnostics;
using System.IO;
using System.Windows.Threading;
using System.Reflection;

namespace ApplicationScheduler
{
    public partial class MainWindow
    {
        #region Global Variables
        List<MyProcess> applicationsList = new List<MyProcess>();
        List<int> hourList, minuteList, secondList;
        int instanceCount;
        bool isHour;
        bool isMinute;
        bool isSecond;
        DispatcherTimer timer;

        private System.Windows.Forms.NotifyIcon TrayNotify;
        private System.Windows.Forms.ContextMenuStrip ctxTrayMenu;
        private bool isAppExiting;
        #endregion

        #region Constructor
        public MainWindow()
        {
            InitializeComponent();

            btnAddApplication.IsEnabled = false;
            btnRemoveApplication.IsEnabled = false;
            btnSchedule.IsEnabled = false;
            btnRunNow.IsEnabled = false;
            
            hourList = new List<int> {  00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 
                                        10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 
                                        20, 21, 22, 23 };
            minuteList = new List<int> {  00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 
                                        10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 
                                        20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
                                        30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
                                        40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
                                        50, 51, 52, 53, 54, 55, 56, 57, 58, 59 };
            secondList = minuteList;
            cmbHour.ItemsSource = hourList;
            cmbMinute.ItemsSource = minuteList;
            cmbSecond.ItemsSource = secondList;

            timer = new DispatcherTimer();
            timer.Tick += TimerTick;

            if (File.Exists(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "\\" + "AppScheduleConfig.txt"))
            {
                var testFileContent = File.ReadAllText(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "\\" + "AppScheduleConfig.txt");
                if (!string.IsNullOrEmpty(testFileContent))
                {
                    ReadFromFile();
                }
            }

            if (lbApplications.Items.Count > 0)
            {
                timer.Interval = TimeSpan.FromMilliseconds(200);
                timer.Start();
            }
        }
        #endregion

        #region Timer-tick-timer
        void TimerTick(object sender, EventArgs e)
        {
            if (lbApplications.Items.Count > 0)
            {
                for (var i = 0; i < lbApplications.Items.Count; i++)
                {
                    var myProcess = lbApplications.Items[i] as MyProcess;
                    var userTime = Convert.ToDateTime(myProcess.StartTime);
                    var currentTime = DateTime.Now;
                    var userTimeString = userTime.ToLongTimeString();
                    var currentTimeString = currentTime.ToLongTimeString();
                    if (currentTimeString.Equals(userTimeString))
                        Process.Start(myProcess.Name);
                }
            }
        } 
        #endregion

        #region Button-Click-btnBrowseProcess
        private void BtnBrowseProcessClick(object sender, RoutedEventArgs e)
        {
            var ofd = new System.Windows.Forms.OpenFileDialog {Filter = "Application files (*.exe)|*.exe"};
            if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                txtApplicationPath.Text = ofd.FileName;
            }
        } 
        #endregion

        #region Button-Click-btnRunProcessNow
        private void BtnRunProcessNowClick(object sender, RoutedEventArgs e)
        {
            if (lbApplications.ItemsSource!=null)
            {
                foreach (MyProcess item in lbApplications.Items)
                {
                    Process.Start(item.Name);
                }
            }
        } 
        #endregion

        #region Button-Click-btnAddProcess
        private void btnAddProcess_Click(object sender, RoutedEventArgs e)
        {
            if (!string.IsNullOrEmpty(txtApplicationPath.Text))
            {
                var scheduledTime = new 
                    DateTime
                    (
                        DateTime.Now.Year, 
                        DateTime.Now.Month, 
                        DateTime.Now.Day, 
                        Convert.ToInt32(cmbHour.SelectedItem), 
                        Convert.ToInt32(cmbMinute.SelectedItem), 
                        Convert.ToInt32(cmbSecond.SelectedItem)
                    );

                var some = new ExeToImageIconConverter(txtApplicationPath.Text);
                var imgSource = some.Icon;

                applicationsList.Add(
                    new MyProcess 
                    { 
                        Name = txtApplicationPath.Text, 
                        StartTime = scheduledTime.ToLongTimeString(),
                        ExeIcon = imgSource
                    });
                txtApplicationPath.Text = string.Empty;
            }
            lbApplications.ItemsSource = null;
            lbApplications.ItemsSource = applicationsList;
            cmbHour.SelectedIndex = -1;
            cmbMinute.SelectedIndex = -1;
            cmbSecond.SelectedIndex = -1;
            btnAddApplication.IsEnabled = false;
        } 
        #endregion

        #region TextBox-TextChanged-txtProcessPath
        private void TxtProcessPathTextChanged(object sender, TextChangedEventArgs e)
        {
            if (string.IsNullOrEmpty(txtApplicationPath.Text))
            {
                btnAddApplication.IsEnabled = false;
            }
            else
            {
                if (isHour && isMinute && isSecond && !string.IsNullOrEmpty(txtApplicationPath.Text))
                {
                    btnAddApplication.IsEnabled = true;
                }
            }
        } 
        #endregion

        #region Button-Click-btnRemoveApplication
        private void BtnRemoveApplicationClick(object sender, RoutedEventArgs e)
        {
            if (lbApplications.ItemsSource != null)
            {
                if (lbApplications.SelectedIndex != -1)
                {
                    foreach (var item in applicationsList)
                    {
                        if (item.Name.Equals((lbApplications.SelectedItem as MyProcess).Name))
                        {
                            applicationsList.Remove(item);
                            WriteToFile(applicationsList);
                            lbApplications.ItemsSource = null;
                            lbApplications.ItemsSource = applicationsList;
                            lbApplications.SelectedIndex = -1;
                            btnRemoveApplication.IsEnabled = false;
                            break;
                        }
                    }
                }
            }
        } 
        #endregion

        #region Button-Click-btnSchedule
        private void BtnScheduleClick(object sender, RoutedEventArgs e)
        {
            instanceCount = 1;
            SaveAndMinimizeToTray();
        }
        #endregion

        #region ComboBox-SelectionChanged-cmbHour,cmbMinute,cmbSecond
        private void TimeSelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            var cmb = sender as ComboBox;
            var controlType = cmb.Name;
            switch (controlType)
            {
                case "cmbHour":
                    isHour = cmb.SelectedIndex != -1;
                    break;
                case "cmbMinute":
                    isMinute = cmb.SelectedIndex != -1;
                    break;
                case "cmbSecond":
                    isSecond = cmb.SelectedIndex != -1;
                    break;
            }
            if (isHour && isMinute && isSecond && !string.IsNullOrEmpty(txtApplicationPath.Text))
            {
                btnAddApplication.IsEnabled = true;
            }
        } 
        #endregion

        #region ListBox-SelectionChanged-lbApplications
        private void LbApplicationsSelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (lbApplications.Items.Count > 0)
            {
                btnRemoveApplication.IsEnabled = lbApplications.SelectedIndex != -1;
            }
        } 
        #endregion

        #region ListBox-LayoutUpdated-lbApplications
        private void LbApplicationsLayoutUpdated(object sender, EventArgs e)
        {
            if (lbApplications.Items.Count > 0)
            {
                btnSchedule.IsEnabled = true;
                btnRunNow.IsEnabled = true;
            }
            if (lbApplications.Items.Count == 0)
            {
                timer.Stop();
            }
        } 
        #endregion

        #region WriteToFile()
        private void WriteToFile()
        {
            if (lbApplications.ItemsSource != null)
            {
                if (lbApplications.Items.Count > 0)
                {
                    var configPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
                    var sw = File.CreateText(configPath + "\\" + "AppScheduleConfig.txt");
                    foreach (MyProcess item in lbApplications.Items)
                    {
                        sw.Write(item.Name + "|" + item.StartTime + "?");
                    }
                    sw.Close();
                }
            }
        }
        #endregion

        #region WriteToFile(List<MyProcess>)
        private void WriteToFile(List<MyProcess> updatedList)
        {
            if (updatedList.Count > 0)
            {
                var configPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
                var sw = File.CreateText(configPath + "\\" + "AppScheduleConfig.txt");

                foreach (MyProcess item in updatedList)
                {
                    sw.Write(item.Name + "|" + item.StartTime + "?");
                }
                sw.Close();
            }
            if (updatedList.Count == 0)
            {
                var configPath = Environment.GetFolderPath(System.Environment.SpecialFolder.MyDocuments);
                var sw = File.CreateText(configPath + "\\" + "AppScheduleConfig.txt");
                sw.Write("");
                sw.Close();
            }
        } 
        #endregion

        #region ReadFromFile()
        private void ReadFromFile()
        {
            var configPath = Environment.GetFolderPath(System.Environment.SpecialFolder.MyDocuments);

            var sr = File.OpenText(configPath + "\\" + "AppScheduleConfig.txt");
            var fileContent = sr.ReadLine();
            var words = fileContent.Split('?');

            applicationsList.Clear();
            for (var i = 0; i < words.Length - 1; i++)
            {
                if (words.Any())
                {
                    var splitWords = words[i].Split('|');

                    var some = new ExeToImageIconConverter(splitWords[0]);
                    var imgSource = some.Icon;

                    applicationsList.Add(
                        new MyProcess 
                            { 
                                Name = splitWords[0], 
                                StartTime = splitWords[1],
                                ExeIcon= imgSource
                            });
                }
            }
            sr.Close();
            lbApplications.ItemsSource = applicationsList;
        }
        #endregion

        #region SaveAndMinimizeToTray()
        private void SaveAndMinimizeToTray()
        {
            WriteToFile();

            TrayNotify = new System.Windows.Forms.NotifyIcon
                             {
                                 Icon =
                                     new System.Drawing.Icon(Assembly.GetExecutingAssembly().Location +
                                                             "..\\..\\Application.ico"),
                                 Visible = true
                             };
            ctxTrayMenu = new System.Windows.Forms.ContextMenuStrip();

            var mnuExit = new System.Windows.Forms.ToolStripMenuItem {Text = "Exit"};
            mnuExit.Click += MnuExitClick;

            var mnuSettings = new System.Windows.Forms.ToolStripMenuItem {Text = "Settings"};
            mnuSettings.Click += MnuSettingsClick;

            var mnuStop = new System.Windows.Forms.ToolStripMenuItem();

            ctxTrayMenu.Items.Add(mnuSettings);
            ctxTrayMenu.Items.Add("-");
            ctxTrayMenu.Items.Add("-");
            ctxTrayMenu.Items.Add(mnuExit);

            TrayNotify.DoubleClick += TrayNotifyDoubleClick;

            TrayNotify.ContextMenuStrip = ctxTrayMenu;

            WindowState = WindowState.Minimized;
            ShowInTaskbar = false;

            TrayNotify.BalloonTipIcon = System.Windows.Forms.ToolTipIcon.Info;
            TrayNotify.BalloonTipTitle = "Application Scheduler";
            TrayNotify.BalloonTipText = "Your Settings have been Saved.";
            TrayNotify.ShowBalloonTip(200);
        }
        #endregion

        #region Menu Click [System Tray Exit]
        void MnuExitClick(object sender, EventArgs e)
        {
            isAppExiting = true;
            Close();
            TrayNotify.Visible = false;
        }
        #endregion

        #region Menu Click [System Tray Settings]
        void MnuSettingsClick(object sender, EventArgs e)
        {
            isAppExiting = false;
            Show();
            ShowInTaskbar = true;
            WindowState = WindowState.Normal;
            TrayNotify.Visible = false;
        }
        #endregion

        #region TrayIcon DoubleClick [System Tray Icon]
        void TrayNotifyDoubleClick(object sender, EventArgs e)
        {
            isAppExiting = false;
            Show();
            ShowInTaskbar = true;
            WindowState = WindowState.Normal;
            TrayNotify.Visible = false;
        }
        #endregion

        #region Window StateChanged [MainWindow]
        private void GlassWindow_StateChanged(object sender, EventArgs e)
        {
            if (instanceCount != 1)
            {
                if (WindowState == WindowState.Minimized)
                {
                    SaveAndMinimizeToTray();
                }
            }
            instanceCount = 0;
        }
        #endregion

        #region Image-MouseLeftButtonDown-Image
        private void ImageMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            Window aboutWindow = new About();
            aboutWindow.ShowDialog();
        } 
        #endregion
    }

    #region Class-MyProcess
    public class MyProcess
    {
        public string Name { get; set; }
        public string StartTime { get; set; }
        public ImageSource ExeIcon { get; set; }
    }
    #endregion

    public class ExeToImageIconConverter
    {
        private string exePath;
        private ImageSource icon;

        public string ExePath { get { return exePath; } }

        public ImageSource Icon
        {
            get
            {
                if (icon == null && File.Exists(ExePath))
                {
                    using (System.Drawing.Icon sysicon = System.Drawing.Icon.ExtractAssociatedIcon(ExePath))
                    {
                        icon = System.Windows.Interop.Imaging.CreateBitmapSourceFromHIcon(
                                  sysicon.Handle,
                                  Int32Rect.Empty,
                                  System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
                    }
                }

                return icon;
            }
        }

        public ExeToImageIconConverter(string exePath)
        {
            this.exePath = exePath;
        }
    }
}
